package observer;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Effective Java 67
 *
 * @author Jly
 * @date 2018/12/13  14:03
 */
public class ObservableSet<E> extends ForwardingSet<E> {

    public ObservableSet(Set<E> s) {
        super(s);
    }

    /**
     * 观察者类集合
     */
//    private final List<SetObserver<E>> observers = new ArrayList<>();

    // 改进test2 抛出的异常不会出现
    // 但是死锁还是会出现，需要在addObserver、removeObserver、notifyElementAdded注释掉synchronized (observers) 代码
    private final List<SetObserver<E>> observers = new CopyOnWriteArrayList<>();

    public void addObserver(SetObserver<E> observer) {
//        synchronized (observers) {
            observers.add(observer);
//        }
    }

    public boolean removeObserver(SetObserver<E> observer) {
//        synchronized (observers) {
            return observers.remove(observer);
//        }
    }

    // This method is the culprit

    /**
     * 通知元素已被添加
     * @param element
     */
    private void notifyElementAdded(E element) {
//        synchronized (observers) {
            for (SetObserver<E> observer : observers)
                observer.added(this, element);
//        }
    }

    private void notifyElementAdded2(E element) {
        List<SetObserver<E>> snapshot;
        synchronized (observers) {
            //这里拍一个快照,
            // 这样我们遍历的时候就不用对原来的集合进行上锁了
            snapshot = new ArrayList<>(observers);
        }
        /**
         * 避开了死锁
         */
        for (SetObserver<E> observer : snapshot)
            observer.added(this, element);
    }

    /**
     * 我的解决办法
     * (这里是没有使用迭代器的问题)
     * *******************错误代码，不仅仅是要使用迭代器，还要显式使用迭代器的 remove
     *                    方法可以在运行期间删除集合元素，不抛出异常
     * @param element
     */
    private void notifyElementAdded3(E element) {
        synchronized (observers) {
            Iterator<SetObserver<E>> iterator = observers.iterator();
            while (iterator.hasNext()){
                SetObserver<E> observer = iterator.next();
                observer.added(this, element);
            }
        }
    }

    @Override
    public boolean add(E e) {
        //调用父类函数添加到集合中
        boolean added = super.add(e);
        if (added) {
            //添加成功,观察者保存注册对象
            notifyElementAdded(e);
//            notifyElementAdded2(e);
//            notifyElementAdded3(e);
        }

        return added;
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        boolean result = false;
        for (E element : c) {
            //做或运算，只要有一个add添加成功，那么result就是true
            result |= add(element);
        }
        return result;
    }
}
